{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Populating the interactive namespace from numpy and matplotlib\n",
      "<Response [200]>\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAADHCAYAAADifRM/AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nO3de3SU1b3/8feXAOESLgm5NBIlIQRabCVcVDj8FC89qNSKnrMMl0qhC+WcBa4DrT0Va9Vju1B0idqzVmWVHq0cq2BaW7EerFq8FUUUEAQC4ZILCbnMQMJVDBD27488CZP7ZWayn3nm+1pr1sw888zMJyF8Z89+9rO3GGNQSinlLT1sB1BKKRV6WtyVUsqDtLgrpZQHaXFXSikP0uKulFIepMVdKaU8KGzFXURuFpF8ETkgIkvD9T5KKaWak3CMcxeRGGAf8M9AKfA5MMsYkxfyN1NKKdVMuFruVwEHjDEFxpizwFpgepjeSymlVBPhKu5DgZKA+6XONqWUUt2gZ5heV1rY1qj/R0QWAAsAYmNjxw8dqrVfKaU6o6Cg4IgxJqmlx8JV3EuBSwPupwFlgTsYY1YBqwAyMzPN8uXLwxRFKaW8KScnp7i1x8JV3D8HskQkAzgMzARmh+m9IkJBQQGff/45+fn5HDx4kDNnzgCQkZHBsGHDGu3r9/tbfZ3z589TVVXV6uNtPdeWpKQWGxYA9O3blwEDBnT5uXFxca0+npyc3OpjU6ZMafUxpbwgLMXdGHNeRO4F3gZigBeMMbvD8V42VFdXc/DgQQ4ePEh+fj67du1qeGzcuHGMGDGCUaNGkZmZSb9+/QAYPnw4w4cPtxXZOr/fz1dffUVlZSVnzpzB5/Ph9/s5evQoFy5caLjfkgEDBpCSkkJsbCxJSUkkJSWRnJxMjx49SEhIIDk5uc0PgdacOXOGd999l7feeotjx45xww03MHXq1GYftkpForAMhewsN3bL7Ny5k08//ZQDBw5QWFgIQJ8+fcjMzGTSpElkZmaSmZlpOaW7HTlyhGXLlpGenk52djZ9+vThG9/4Bv369etSMe4OH3/8MStXruTs2bOMHz+eRYsWtfntQCmbcnJythpjJrT0WLi6ZSLWb3/7W9577z3uv/9+7rnnHttxItJ///d/s3HjRmbMmMEzzzxjO06nTJ48mcmTJzfcf/PNN3nrrbfw+/0MGzaMRYsWkZ6ebi+gUh2kLXfHP/7xD1566SVWrFjRZh+wall1dTWPPfYYZWVlrF69mp49vdlu2LRpE+vXryc/P5+xY8cydepUxo8fbzuWilJttdyjvrjPnj2bxx9/XPtZu2j//v0sX76c559/3nYUa5YvX05mZiZ33nlnh5+zYcMG1q1bR21tLRC6A+EiwquvvhqS11Lup90yrcjJySE3N9d2jIj117/+lc8++yyqCzvA0qVLyc3NpaamhtjY2Bb3OXbsGK+++iobNmxg0qRJzJw5kxtvvDEseXJycli7di09eui8gNEsalvu+h8gOE888QRpaWn84Ac/sB3FNebMmcNTTz1FSkoKAFu3bmXt2rUUFxczZ84cbr31VkRaOr8v9PTvOzpoyz3AunXrqKio0BZ7EGpra/npT39KTEyM7SiusXfvXi5cuMCSJUu47bbbmDVrFuPHj7fWH5+bm8v69eu56aab9N8pSkVdcV+7di1r1qyxHSOi3X333fz+97+3HcO6J554gq1bt3LZZZcxY8YMXn75ZduRGpk2bRozZszQPvgoFXXF/bnnnrMdIaIdOnSICxcukJOT0+LjMTExJCYmkpiY2DCWvf6ko/j4eBITE+nVq5drx7m3paKigocffphjx45x/fXXc//999uO1K6XX36ZpUuXYns0mup+UVXcV6xYwX333Wc7RkT76U9/2qUuLb/fT1VVFYWFhZw/f77hjNSTJ0/y9ddfNztDderUqUyYMIHs7OxQxu+03/72t2zYsIFBgwaRk5PDqlWrrObprJ49e1JbW0ttba12z0SZqDmgunv3boqKivje974X1vfxsnnz5vHiiy9aee9//OMfbN68mS1btnDhwgXGjRvHhAkTmDhxYsjPIP3666/54Q9/yPPPP++Zcx60e8ab9IAqsGzZMl555RXbMVQXXXPNNVxzzTWNtvn9fj788ENee+01Tp06xR133MGsWbOCfq/Fixd77oD7ihUreOmll5gzZ47tKKqbRE1xrz9ZRHXdj370I9sRGklKSuJ73/tew7exr776irlz52KM4Z577mn2YdCe8vJylixZ4skWblpaGn/961+1uEeRqCjuJSUlLFy40HaMiHb8+HHXT5Pbr18/Vq9e3XC/srKS5557jj179jBt2jTmzZvX6nNnzJjBK6+84snC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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Response [200]>"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import requests\n",
    "%pylab inline\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.image as mpimg\n",
    "from PIL import Image\n",
    "from io import BytesIO\n",
    "\n",
    "\n",
    "# These two work in the database.sh script, but passing a file through the requests library was not working.\n",
    "# So you have to manually create the db_connection in GeoServer\n",
    "\n",
    "# def create_db_conn(config_xml):\n",
    "#     headers = {'content-type': 'text/xml'}\n",
    "#     files = {'config.xml': open(config_xml, 'r')}\n",
    "#     r1 = requests.post(\"http://localhost:8080/geoserver/rest/workspaces/upc/datastores\", \n",
    "#     auth=('admin', 'geoserver'), \n",
    "#     files=files,\n",
    "#     headers=headers)\n",
    "#     return r1\n",
    "    #requests.get(\"curl -v -u admin:geoserver -XPOST -T\" + config.xml + \"-H 'Content-type: text/xml' http://localhost:8080/geoserver/rest/workspaces/upc/datastores\")\n",
    "\n",
    "# def access_db_info(workname, dbname):\n",
    "#     headers = {'content-type': 'text/xml'}\n",
    "#     r1 = requests.get(\"http://localhost:8080/geoserver/rest/workspaces/\" + workname + \"/datastores/\" + dbname + '.xml', \n",
    "#     auth=('admin', 'geoserver'), \n",
    "#     headers=headers)\n",
    "#     return r1\n",
    "\n",
    "\n",
    "# The below function corresponds to this script\n",
    "# curl -v -u admin:geoserver -XPOST -H 'Content-type: text/xml' -d '<workspace><name>\" + name + \"</name></workspace>' http://localhost:8080/geoserver/rest/workspaces\")\n",
    "\n",
    "\n",
    "def create_workspace(name):\n",
    "     \"\"\"\n",
    "    This creates a workspace in the geoserver instance, this is not required as there are several others\n",
    "    that are default like 'cite'\n",
    "    Parameters\n",
    "    ----------\n",
    "    name : str\n",
    "         Workspace name\n",
    "    Returns\n",
    "    -------\n",
    "     : GeoServer Workspace\n",
    "    \"\"\"\n",
    "    headers = {'content-type': 'text/xml'}\n",
    "    r1 = requests.post(\"http://localhost:8080/geoserver/rest/workspaces\", \n",
    "    auth=('admin', 'geoserver'), \n",
    "    data='<workspace><name>' + name + '</name></workspace>',\n",
    "    headers=headers)\n",
    "    return r1\n",
    "\n",
    "\n",
    "\n",
    "# curl -v -u admin:geoserver -XPOST -H \"Content-type: text/xml\" -d \"<featureType><name>datafiles_w_footprints</name></featureType>\" http://localhost:8080/geoserver/rest/workspaces/upc/datastores/upcdev/featuretypes\n",
    "\n",
    "\n",
    "\n",
    "def publish_table(tablename):\n",
    "      \"\"\"\n",
    "    This function makes a certain table in a database accessible via all services (WFS, REST, etc.) \n",
    "    If you want to create new SQL views, this must be done first\n",
    "    Parameters\n",
    "    ----------\n",
    "    tablename : str\n",
    "         Database Table name\n",
    "    Returns\n",
    "    -------\n",
    "     : A published database table on your running GeoServer instance\n",
    "    \"\"\"\n",
    "    headers = {'content-type': 'text/xml'}\n",
    "    url = \"http://localhost:8080/geoserver/rest/workspaces/cite/datastores/upcdev/featuretypes\"\n",
    "    r1 = requests.post(url, \n",
    "    auth=('admin', 'geoserver'), \n",
    "    data='<featureType><name>' + tablename + '</name></featureType>',\n",
    "    headers=headers)\n",
    "    return r1\n",
    "\n",
    "def create_new_sql_view(layer_name, sql_command=\"select * FROM datafiles_w_footprints WHERE instrumentid=21\"):\n",
    "    \"\"\"\n",
    "    This takes in a SQL command and returns and adds a view on the GeoServer instance that you have running. \n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    layer_name : str\n",
    "         The name you want the layer returned to be called\n",
    "    \n",
    "    sql_command : str\n",
    "         Any valid SQL statement\n",
    "    Returns\n",
    "    -------\n",
    "     : A new layer called 'layer_name' on your running GeoServer instance\n",
    "    \"\"\"\n",
    "    headers = {'content-type': 'text/xml'}\n",
    "    \n",
    "    # The Geometry column will probably need adjusting depending on the database and table \n",
    "    data =  \"<featureType><name>\" + layer_name + \"</name>\" + \\\n",
    "            '''<nativeName>''' + layer_name + '''</nativeName>\n",
    "            <namespace>\n",
    "            <name>cite</name>\n",
    "            <atom:link xmlns:atom='http://www.w3.org/2005/Atom' rel='alternate' href='http://arizona-umh.cs.umn.edu:8080/geoserver/rest/namespaces/cite.xml' type='application/xml'/> \\\n",
    "            </namespace>\n",
    "            <title>''' + layer_name + '''</title>\n",
    "            <keywords>\n",
    "            <string>features</string>\n",
    "            <string>''' + layer_name + '''</string>\n",
    "            </keywords>\n",
    "            <projectionPolicy>FORCE_DECLARED</projectionPolicy>\n",
    "            <enabled>true</enabled>\n",
    "            <metadata>\n",
    "            <entry key='JDBC_VIRTUAL_TABLE'>\n",
    "            <virtualTable>\n",
    "            <name>''' + layer_name + '''</name>\n",
    "            <sql>''' + sql_command + '''</sql>\n",
    "            <escapeSql>true</escapeSql>\n",
    "            <geometry>\n",
    "            <name>footprint</name>\n",
    "            <type>Geometry</type>\n",
    "            <srid>-1</srid>\n",
    "            </geometry>\n",
    "            <geometry>\n",
    "            <name>centroid</name>\n",
    "            <type>Geometry</type>\n",
    "            <srid>-1</srid>\n",
    "            </geometry>\n",
    "            </virtualTable>\n",
    "            </entry>\n",
    "            <entry key='cachingEnabled'>false</entry>\n",
    "            </metadata>\n",
    "            <store class='dataStore'>\n",
    "            <name>cite:upcdev</name>\n",
    "            <atom:link xmlns:atom='http://www.w3.org/2005/Atom' rel='alternate' href='http://arizona-umh.cs.umn.edu:8080/geoserver/rest/workspaces/cite/datastores/AlwaysShen.xml' type='application/xml'/> \\\n",
    "            </store>\n",
    "            </featureType>'''\n",
    "    \n",
    "    # The URL runs off the default 'cite' workspace, but it uses a 'store' named 'upcdev' which you created \n",
    "    # When you run the publish_table() function above, so if you change upcdev as the name, then you also\n",
    "    # Have to change it here\n",
    "    url = \"http://localhost:8080/geoserver/rest/workspaces/cite/datastores/upcdev/featuretypes\"\n",
    "    r1 = requests.post(url, \n",
    "    auth=('admin', 'geoserver'),\n",
    "    headers=headers, data=data)\n",
    "    return r1\n",
    "\n",
    "# wget http://localhost:8080/geoserver/wms/reflect?layers=upc:datafiles_w_footprints\n",
    "\n",
    "\n",
    "def get_image(layer_name):\n",
    "    \"\"\"\n",
    "    This is a function that serves as an example that the request can actually render images from GeoServer\n",
    "    The layer_name is the view you created above with create_new_sql_view()\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    layer_name : str\n",
    "         The name of the layer you want to preview\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "     : A rendered image of the layer_name you specified\n",
    "    \"\"\"\n",
    "    url = \"http://localhost:8080/geoserver/wms/reflect?layers=cite:\" \n",
    "    r1 = requests.get(url + layer_name)\n",
    "    im = Image.open(BytesIO(r1.content))\n",
    "    plt.imshow(im)\n",
    "    plt.show()\n",
    "    return r1\n",
    "\n",
    "# dbcreate = create_workspace(\"upc\")\n",
    "# x = publish_table(\"datafiles_w_footprints\")\n",
    "# print(x)\n",
    "\n",
    "create_new_sql_view('voyager4')\n",
    "get_image('voyager4')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
